#include "Partida.h"
#include <math.h>
#include "Fantasma.h"
#include <SDL_mixer.h>


bool comiendo1 = false;
int tiempoComiendo1 = 0; //ms
bool comiendo2 = false;
int tiempoComiendo2 = 0; //ms

Partida::Partida() {
	escenario = NULL;
	periodoDeRefresco = 10;//ms
    Running = true;
	tiempoJugado = 0;//ms
	tiempoDeEvento=0;
	frecuenciaDeAparicion = this->escenario->getFrecuenciaDeAparicionDeBonus();
	bonusFactory = new BonusFactory(this->escenario->getListaDeTiposBonus());
}

Partida::Partida(Jugador* j1, Jugador* j2) {
	jugador1 = j1;
	jugador2 = j2;
	escenario = NULL;
	periodoDeRefresco = 10;//ms
	tiempoJugado = 0;//ms
    Running = true;
	tiempoDeEvento=0;
	frecuenciaDeAparicion = this->escenario->getFrecuenciaDeAparicionDeBonus();
	bonusFactory = new BonusFactory(this->escenario->getListaDeTiposBonus());
}

Partida::Partida(Escenario* e) {
	escenario = e;
    Running = true;
	mapa = new MapaDeCeldas(escenario);
	periodoDeRefresco = 10; //ms
	tiempoJugado = 0; //ms
	tiempoDeEvento=0;
	frecuenciaDeAparicion = e->getFrecuenciaDeAparicionDeBonus();
	bonusFactory = new BonusFactory(e->getListaDeTiposBonus());
}

Partida::~Partida(){
	delete this->bonusFactory;
	delete this->dibujador;
	delete this->mapa;

	for(int i=0;i<4;i++){
		delete fantasmas1[i];
	}

	for(int i=0;i<4;i++){
		delete fantasmas2[i];
	}
	delete this->escenario;

}


void Partida::OnKeyDown(SDLKey sym, SDLMod mod, Uint16 unicode) {
tiempoDeEvento = 500;
	switch(sym){
		case SDLK_a:
				jugador1->getPacman()->setSiguienteDireccion(2,mapa);
			break;
		case SDLK_s:
				jugador1->getPacman()->setSiguienteDireccion(1,mapa);
			break;
		case SDLK_d:
				jugador1->getPacman()->setSiguienteDireccion(0,mapa);
			break;
		case SDLK_w:
				jugador1->getPacman()->setSiguienteDireccion(3,mapa);
			break;
		case SDLK_UP:
				jugador2->getPacman()->setSiguienteDireccion(3,mapa);
			break;
		case SDLK_DOWN:
				jugador2->getPacman()->setSiguienteDireccion(1,mapa);
			break;
		case SDLK_RIGHT:
				jugador2->getPacman()->setSiguienteDireccion(0,mapa);
			break;
		case SDLK_LEFT:
				jugador2->getPacman()->setSiguienteDireccion(2,mapa);
			break;
		case SDLK_1:
			congelarFantasmas();
			break;
		case SDLK_2:
			descongelarFantasmas();
			break;
		case SDLK_RETURN:
			if (terminoElJuego()) {
				Running = false;
			}
			break;

	}

}

void Partida::congelarFantasmas() {
	fantasmas1[0]->congelarFantasma();
	fantasmas1[1]->congelarFantasma();
	fantasmas1[2]->congelarFantasma();
	fantasmas1[3]->congelarFantasma();
	fantasmas2[0]->congelarFantasma();
	fantasmas2[1]->congelarFantasma();
	fantasmas2[2]->congelarFantasma();
	fantasmas2[3]->congelarFantasma();
}

void Partida::descongelarFantasmas() {
	fantasmas1[0]->descongelarFantasma();
	fantasmas1[1]->descongelarFantasma();
	fantasmas1[2]->descongelarFantasma();
	fantasmas1[3]->descongelarFantasma();
	fantasmas2[0]->descongelarFantasma();
	fantasmas2[1]->descongelarFantasma();
	fantasmas2[2]->descongelarFantasma();
	fantasmas2[3]->descongelarFantasma();
}

void Partida::setJugadores(Jugador* j1, Jugador* j2){
	jugador1 = j1;
	jugador2 = j2;
	this->jugador1->getPacman()->setPosInicialX(this->escenario->getGrilla()->getPosInicialPacman1X());
	this->jugador1->getPacman()->setPosInicialY(this->escenario->getGrilla()->getPosInicialPacman1Y());
	this->jugador2->getPacman()->setPosInicialX(this->escenario->getGrilla()->getPosInicialPacman2X());
	this->jugador2->getPacman()->setPosInicialY(this->escenario->getGrilla()->getPosInicialPacman2Y());
	inicializarFantasmas();
}

bool Partida::OnInit() {
    if(SDL_Init(SDL_INIT_EVERYTHING) < 0) {
        return false;
    }
	/*cout << this->mapa->getNuevaDireccion(2,3,13,2) << endl;
	system("PAUSE");*/
	//ESTO SE PUEDE SACAR
    dibujador = new Dibujador(escenario);
	dibujador->dibujarEscenario();
	//HASTA ACA
    return true;
}


void Partida::OnRender() {
}

void Partida::OnCleanup() {
	SDL_Quit();
}

void Partida::dibujar(){
	this->dibujador->dibujarEscenario();


	if(tiempoComiendo1!=0){
		tiempoComiendo1-=periodoDeRefresco;
	}
	else{
		comiendo1 = false;
	}
	if(comiendo1){
		this->dibujador->dibujarPacman(this->jugador1->getPacman(),this->mapa,"pacman1c");
	}
	else{
		this->dibujador->dibujarPacman(this->jugador1->getPacman(),this->mapa,"pacman1");
	}

	if(tiempoComiendo2!=0){
		tiempoComiendo2-=periodoDeRefresco;
	}
	else{
		comiendo2 = false;
	}
	if(comiendo2){
		this->dibujador->dibujarPacman(this->jugador2->getPacman(),this->mapa,"pacman2c");
	}
	else{
		this->dibujador->dibujarPacman(this->jugador2->getPacman(),this->mapa,"pacman2");
	}


	dibujarFantasmas();
	this->dibujador->dibujarInformacion(this->jugador1,this->jugador2,tiempoJugado);
	this->dibujador->Flip();
}

void Partida::actualizarEstado(){
	this->jugador1->getPacman()->vivir(this->mapa);
	this->jugador2->getPacman()->vivir(this->mapa);
	actualizarFantasmas();
	chequearBonus();
	if(this->cruzaPacman()){
			SDL_Delay(10);
			Mix_Chunk *sonido;
			Mix_OpenAudio(44100, AUDIO_S16, 2, 4096);
			sonido = Mix_LoadWAV("Pacman_CRUCEFANTASMA_WAV_00.01.wav");
			Mix_PlayChannel(-1, sonido, 0);
	}
}



int Partida::OnExecute() {
    if(OnInit() == false) {
        return -1;
    }

    SDL_Event Event;
	
    while(Running) {
		SDL_Delay(periodoDeRefresco);
		tiempoJugado+=periodoDeRefresco;
		
		//ESTO SE PUEDE SACAR
		dibujar();
		actualizarEstado();

		/*
		 * Si paso el tiempo determinado de frecuencia de aparicion de los bonus, se genera este nuevo bonus
		 * y se desactiva el bonus anterior dejandolo sin efecto.
		 */
		if(tiempoJugado%frecuenciaDeAparicion==0){

			Pacman* pacmanJ1 = this->jugador1->getPacman();
			Pacman* pacmanJ2 = this->jugador2->getPacman();

			Bonus* bonusNuevo = this->bonusFactory->generarBonus();
			if(bonusNuevo!=NULL){
			if(tiempoJugado!=frecuenciaDeAparicion){
			this->dibujador->eliminarBonusDeImagen(this->mapa->getSiguienteBonusX(),this->mapa->getSiguienteBonusY(),this->mapa);
			}
			this->mapa->generarPosicionSiguienteBonus(pacmanJ1->getCeldaX(),pacmanJ1->getCeldaY(),pacmanJ2->getCeldaX(),pacmanJ2->getCeldaY());
			Celda* celdaBonusNuevo = this->mapa->accederACelda(this->mapa->getSiguienteBonusX(),this->mapa->getSiguienteBonusY());
			celdaBonusNuevo->setBonus(bonusNuevo);
			celdaBonusNuevo->setBonusUtilizado(false);
			dibujador->dibujarBonus(bonusNuevo,mapa,mapa->getSiguienteBonusX(),mapa->getSiguienteBonusY());
			}
			/*
			 * Se reestablecen los valores "normales" de los pacman y fantasmas, es decir, se desactivan 
			 * los efectos del bonus comido anteriormente.
			 */
			this->jugador1->getPacman()->reestablecer();
			this->jugador2->getPacman()->reestablecer();
			this->fantasmas1[0]->reestablecer();
			this->fantasmas1[1]->reestablecer();
			this->fantasmas1[2]->reestablecer();
			this->fantasmas1[3]->reestablecer();
			this->fantasmas2[0]->reestablecer();
			this->fantasmas2[1]->reestablecer();
			this->fantasmas2[2]->reestablecer();
			this->fantasmas2[3]->reestablecer();
		}

		if(terminoElJuego()){
			bool gano1 = false;
			string nombreGanador;
			int puntos1 = this->jugador1->getPacman()->getPuntajeObtenido();
			int puntos2 = this->jugador2->getPacman()->getPuntajeObtenido();
			int vidas1 = this->jugador1->getPacman()->getVidas();
			int vidas2 = this->jugador2->getPacman()->getVidas();
			
			// Agregado por Sonido
			// Si gano por muerte del otro pacman, espero a que termine la musica de muerte
			SDL_Delay(1000);
			Mix_Chunk *sonido;
			Mix_OpenAudio(44100, AUDIO_S16, 2, 4096);
			sonido = Mix_LoadWAV("Pacman_VICTORIA_WAV_00.14.wav");
			Mix_PlayChannel(-1, sonido, 0);
			// Fin Agregado por Sonido
			
			if (vidas1==0 || vidas2==0) {
				if (vidas2==0) {
					gano1 = true;
					nombreGanador = this->jugador1->getNombreUsuario();
					this->dibujador->dibujarGameOver(nombreGanador);
				}
				else {
					gano1 = false;
					nombreGanador = this->jugador2->getNombreUsuario();
					this->dibujador->dibujarGameOver(nombreGanador);
				}
			}
			else {
				if (puntos1 > puntos2) {
					gano1 = true;
					nombreGanador = this->jugador1->getNombreUsuario();
					this->dibujador->dibujarGameOver(nombreGanador);
				}
				else {
					nombreGanador = this->jugador2->getNombreUsuario();
					this->dibujador->dibujarGameOver(nombreGanador);
				}
			}
			UsuariosDAO* usuariosDAO = UsuariosDAO::getInstancia();
			usuariosDAO->actualizarEstadisticaDeJugador(this->jugador1->getNombreUsuario(),
				puntos1,gano1,false,this->tiempoJugado);
			usuariosDAO->actualizarEstadisticaDeJugador(this->jugador2->getNombreUsuario(),
				puntos2,!gano1,false,this->tiempoJugado);
				
			usuariosDAO->insertarNuevaPartida(this->jugador1->getNombreUsuario(),this->jugador2->getNombreUsuario(),
					nombreGanador,puntos1,puntos2,this->tiempoJugado);
			
			SDL_Delay(6000);
			Running = false;
		}
		//HASTA ACA
		if(tiempoDeEvento!=0){
			tiempoDeEvento-=periodoDeRefresco;
			OnEvent(&evento);
		}
        while(SDL_PollEvent(&Event)) {
            OnEvent(&Event);
			evento = Event;
        }
    }

    OnCleanup();

    return 0;
}

void Partida::inicializarFantasmas(){
	fantasmas1 = (Fantasma**) malloc(sizeof(Fantasma*)*4);
	fantasmas1[0] = new Fantasma(this->jugador1->getPacman(),19,26);//deshardcodear esto
	fantasmas1[1] = new Fantasma(this->jugador1->getPacman(),27,26);
	fantasmas1[2] = new Fantasma(this->jugador1->getPacman(),13,29);
	fantasmas1[3] = new Fantasma(this->jugador1->getPacman(),2,21);
	fantasmas2 = (Fantasma**) malloc(sizeof(Fantasma*)*4);
	fantasmas2[0] = new Fantasma(this->jugador2->getPacman(),2,26);
	fantasmas2[1] = new Fantasma(this->jugador2->getPacman(),10,26);
	fantasmas2[2] = new Fantasma(this->jugador2->getPacman(),16,29);
	fantasmas2[3] = new Fantasma(this->jugador2->getPacman(),27,21);
}

void Partida::actualizarFantasmas(){

	for(int i=0;i<4;i++){
		fantasmas1[i]->vivir(this->mapa);
	}

	for(int i=0;i<4;i++){
		fantasmas2[i]->vivir(this->mapa);
	}
	
}


bool Partida::cruzaPacman(){
	bool resultado= false;
	float x1= (float)((float)this->jugador1->getPacman()->getPosX())/((float)this->jugador1->getPacman()->getPasosPorCelda());
	float y1= (float)((float)this->jugador1->getPacman()->getPosY())/((float)this->jugador1->getPacman()->getPasosPorCelda());
	float x2= (float)((float)this->jugador2->getPacman()->getPosX())/((float)this->jugador2->getPacman()->getPasosPorCelda());
	float y2= (float)((float)this->jugador2->getPacman()->getPosY())/((float)this->jugador2->getPacman()->getPasosPorCelda());
	
	resultado = ( abs(x2-x1)<0.03f && abs(y2-y1)<0.03f);

	int i = 0;
	while(i<4 && !resultado){
		float x1f = (float) ((float)fantasmas1[i]->getPosX())/((float)fantasmas1[i]->getPasosPorCelda());
		float y1f = (float) ((float)fantasmas1[i]->getPosY())/((float)fantasmas1[i]->getPasosPorCelda());
		float x2f = (float) ((float)fantasmas2[i]->getPosX())/((float)fantasmas2[i]->getPasosPorCelda());
		float y2f = (float) ((float)fantasmas2[i]->getPosY())/((float)fantasmas2[i]->getPasosPorCelda());

		resultado = ( abs(x1-x2f)<0.03f && abs(y1-y2f)<0.03f );
		if(!resultado){
			resultado = ( abs(x2-x1f)<0.03f && abs(y2-y1f)<0.03f);
		}
		i++;
	}
	return resultado;
}

void Partida::dibujarFantasmas(){
	this->dibujador->dibujarFantasma(fantasmas1[0],this->mapa,"fantasma1");
	this->dibujador->dibujarFantasma(fantasmas1[1],this->mapa,"fantasma1");
	this->dibujador->dibujarFantasma(fantasmas1[2],this->mapa,"fantasma1");
	this->dibujador->dibujarFantasma(fantasmas1[3],this->mapa,"fantasma1");
	this->dibujador->dibujarFantasma(fantasmas2[0],this->mapa,"fantasma2");
	this->dibujador->dibujarFantasma(fantasmas2[1],this->mapa,"fantasma2");
	this->dibujador->dibujarFantasma(fantasmas2[2],this->mapa,"fantasma2");
	this->dibujador->dibujarFantasma(fantasmas2[3],this->mapa,"fantasma2");
}

bool Partida::terminoElJuego(){
	
	bool termino = ( mapa->seAcabaronLosBonus() || this->jugador1->getPacman()->getVidas()==0 || this->jugador2->getPacman()->getVidas()==0 );
	return termino;
}

void Partida::chequearBonus(){

	Pacman* pacman1 = this->jugador1->getPacman();
	Pacman* pacman2 = this->jugador2->getPacman();

	int columna1 = pacman1->getCeldaX();
	int fila1 = pacman1->getCeldaY();
	Celda* celda1 = this->mapa->accederACelda(columna1, fila1);
	Bonus* bonusEnCelda1 = celda1->getBonus();

	int columna2 = pacman2->getCeldaX();
	int fila2 = pacman2->getCeldaY();
	Celda* celda2 = this->mapa->accederACelda(columna2, fila2);
	Bonus* bonusEnCelda2 = celda2->getBonus();


	/*
	 * Si el Bonus no fue utilizado entonces se aplica su efecto al Pacman correspondiente y luego
	 * se marca como utilizado.
	 * La verificacion se realiza teniendo en cuenta primero al Pacman del Jugador1 y luego
	 * al Pacman del Jugador2
	 */

	if(!celda1->bonusFueUtilizado()){
		if(true){//bonusEnCelda1->seAplicaAComedor()){
			//bonusEnCelda1->aplicarEfecto(pacman1);
		
			comiendo1 = true;
			tiempoComiendo1 = 40;
			
			if(bonusEnCelda1->getTipo()=="comida"){
				pacman1->aumentarPuntaje(1);
				if(pacman1->isSumaPuntosRival()){
					pacman2->aumentarPuntaje(1);
				}
			}
			
			if(bonusEnCelda1->getTipo()=="reducirVelocidad"){
				pacman2->setVelocidad(Posicionable::VELOCIDAD_LENTO);
			}

			if(bonusEnCelda1->getTipo()=="duplicarVelocidad"){
				pacman1->setVelocidad(Posicionable::VELOCIDAD_RAPIDO);
			}


			if(bonusEnCelda1->getTipo()=="perseguirAFantasmas"){
				this->fantasmas1[0]->setEscapando(true);
				this->fantasmas1[1]->setEscapando(true);
				this->fantasmas1[2]->setEscapando(true);
				this->fantasmas1[3]->setEscapando(true);
			}

			if(bonusEnCelda1->getTipo()=="congelarOponente"){
				pacman2->setEnMovimiento(false);
			}

			if(bonusEnCelda1->getTipo()=="multiplicadorPuntos"){
				pacman1->setMultiplicadorPuntaje(5);
			}

			if(bonusEnCelda1->getTipo()=="sumarPuntosDelOponente"){
				pacman2->setSumaPuntosRival(true);
				pacman1->setSumaPuntosRival(false);
			}

			if ((bonusEnCelda1->getTipo() == "comida") && pacman2->isSumaPuntosRival()){
				pacman2->setMultiplicadorPuntaje(pacman1->getMultiplicadorPuntaje());
				bonusEnCelda1->aplicarEfecto(pacman2);	
			}


			if (bonusEnCelda1->getTipo() == "fantasmasAOponente"){

				this->fantasmas1[0]->modificarPerseguido(pacman2);
				this->fantasmas1[1]->modificarPerseguido(pacman2);
				this->fantasmas1[2]->modificarPerseguido(pacman2);
				this->fantasmas1[3]->modificarPerseguido(pacman2);
			}

		/*	if(bonusEnCelda1->getTipo() == "reducirVelocidad"){
				pacman2->setPasosPorCelda(25);
			}*/

		
		}
		this->dibujador->eliminarBonusDeImagen(columna1,fila1,this->mapa);//Agregado por juan
		celda1->setBonusUtilizado();
	}

	if(!celda2->bonusFueUtilizado()){
		if(true){//bonusEnCelda2->seAplicaAComedor()){
			//bonusEnCelda2->aplicarEfecto(pacman2);

			comiendo2 = true;
			tiempoComiendo2 = 40;

			if(bonusEnCelda2->getTipo()=="reducirVelocidad"){
				pacman1->setVelocidad(Posicionable::VELOCIDAD_LENTO);
			}

			if(bonusEnCelda2->getTipo()=="duplicarVelocidad"){
				pacman2->setVelocidad(Posicionable::VELOCIDAD_RAPIDO);
			}

			if(bonusEnCelda2->getTipo()=="perseguirAFantasmas"){
				this->fantasmas2[0]->setEscapando(true);
				this->fantasmas2[1]->setEscapando(true);
				this->fantasmas2[2]->setEscapando(true);
				this->fantasmas2[3]->setEscapando(true);
			}

			if(bonusEnCelda2->getTipo()=="sumarPuntosDelOponente"){
				pacman1->setSumaPuntosRival(true);
				pacman2->setSumaPuntosRival(false);
			}

			if(bonusEnCelda2->getTipo()=="congelarOponente"){
				pacman1->setEnMovimiento(false);
			}

			if(bonusEnCelda2->getTipo()=="multiplicadorPuntos"){
				pacman2->setMultiplicadorPuntaje(5);
			}

			if(bonusEnCelda2->getTipo()=="comida"){
				pacman2->aumentarPuntaje(1);
				if(pacman2->isSumaPuntosRival()){
					pacman1->aumentarPuntaje(1);
				}
			}


			if ((bonusEnCelda2->getTipo() == "comida") && pacman1->isSumaPuntosRival()){
				pacman1->setMultiplicadorPuntaje(pacman2->getMultiplicadorPuntaje());
				bonusEnCelda2->aplicarEfecto(pacman1);	
			}


			if (bonusEnCelda2->getTipo() == "fantasmasAOponente"){

				this->fantasmas2[0]->modificarPerseguido(pacman1);
				this->fantasmas2[1]->modificarPerseguido(pacman1);
				this->fantasmas2[2]->modificarPerseguido(pacman1);
				this->fantasmas2[3]->modificarPerseguido(pacman1);

			} 

			/*if(bonusEnCelda2->getTipo() == "reducirVelocidad"){
				pacman1->setPasosPorCelda(25);
			}*/

		}
		this->dibujador->eliminarBonusDeImagen(columna2,fila2,this->mapa);//Agregado por juan
		celda2->setBonusUtilizado();
	}

}
